package org.lisy.java.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

/**
 * 线程操作
 * 
 * @author lisy
 */
public class ThreadOperate {
	/**
	 * 创建线程方式：
	 * 	1.实现 Runnable 接口创建线程
	 * 	2.继承 Thread 类创建线程
	 * 	3.使用 Callable 和 Future 创建线程
	 * 	4.使用线程池例如用 Executor 框架
	 */
	
	/**
	 * 线程的状态：
	 * 	1.新建状态 New
	 * 	2.运行状态 Runnable，包括就绪(Ready) 和 运行(Runing)
	 * 	3.阻塞状态 Blocked
	 * 	4.等待状态 Waiting
	 *  5.超时等待状态 Time_waiting
	 * 	6.中止状态 Terminated
	 */
	
	/**
	 * 同步锁 synchronized
	 * 	1.修饰方法：在定义接口方法和构造方法时不能使用 synchronized 关键字
	 * 		public synchronized void method(){ // todo }
	 * 	2.修饰代码块：
	 * 		public void method(){ synchronized(this) { // todo } }
	 * 	3.修饰静态方法：锁定类的所有对象
	 * 		public synchronized static void method() { // todo }
	 * 	4.修饰类：与给静态方法加锁是一样的，所有对象公用一把锁
	 * 		class ClassName {public void method() {synchronized(ClassName.class) { // todo}}}
	 * 悲观锁：加锁
	 * 乐观锁：不加锁，对比版本号
	 * 自旋锁：短时间占有锁，可以减少CPU上下文切换
	 * 可重入锁：外层函数获取锁后，内层函数还可以获取
	 * 公平锁(fair lock)：分配锁前检查是否有线程在排队优先分配给排队时间最长的线程
	 * 非公平锁(nonfair lock)：不考虑等待队列，直接尝试获取锁
	 * 读写锁
	 * 独占锁和共享锁
	 * 重量级锁和轻量级锁：重量级锁是基于操作系统的互斥量(mutex lock)实现的，开销较大
	 * 偏向锁：一个锁被同一个线程多次获取，消除线程锁重入的开销(减少CAS	次数)
	 * 分段锁：锁细化思想，提高并发效率
	 * 死锁：互相等待对方释放资源，加超时状态
	 * 锁优化常用方法：减少持有锁时间、锁细化、锁粗化、锁分离、锁消除
	 */
	
	/**
	 * 线程调度
	 * 1. 抢占式调度
	 * 2. 协同式调度
	 * 进程调度算法
	 * 1. 优先调度算法：先来先服务调度算法、短作业优先调度算法
	 * 2. 高优先权先调度算法
	 * 3. 时间片的轮转调度算法
	 */
	
	/**
	 * volatile
	 * 1. 保证线程的可见性(cpu缓存一致性)
	 * 2. 防止指令重排序(读屏障/写屏障)
	 */
	
	/**
	 * 线程常用方法：
	 * isAlive()：
	 * 		判断线程是否还未终止
	 * getPriority()：
	 * 		获取线程的优先级数值，返回值
	 * setPriority()：
	 * 		设置线程的优先级，默认是 5，频繁阻塞(休眠或IO)的线程设置高优先级，偏重计算的设置低优先级
	 * Thread.sleep()：
	 * 		将当前线程睡眠指定毫秒数，会抛异常
	 * Thread.interrupt：
	 * 		打断 sleep，通过 interrupt 方法和 isInterrupted() 方法来停止正在运行的线程
	 * 		一般情况下不建议通过这种方式来中断线程，一般会在自定义 Thread 类中增加一个属性 isStop 来标志是否结束，然后再在工作循环中判断 isStop 的值
	 * join()：
	 * 		调用某线程的该方法，将当前线程与该线程“合并”，如果调用的是无参 join 方法，则等待 thread 执行完毕，如果调用的是指定了时间参数的 join 方法，则等待一定的时间
	 * yield()：
	 * 		让出cpu，当前线程进入就绪队列等待调度，yield 方法只能让拥有相同优先级的线程有获取 CPU 执行时间的机会
	 * wait()：
	 * 		当前线程进去对象的等待队列（wait pool）
	 * notify()/notifyAll()：
	 * 		唤醒对象的 wait pool 中的一个或所有等待线程
	 * setDaemon()：
	 * 		设置是否为守护线程。守护线程和用户线程的区别在于：守护线程依赖于创建它的线程，而用户线程则不依赖
	 *      注意: 需要在启动线程之前设置，不能在启动线程之后设置
	 * getState()：
	 *      获取线程状态
	 * ThreadLocal: 
	 *      线程变量，以 ThreadLocal 对象为键、任意对象为值的存储结构
	 * Thread 类有一个比较常用的静态方法 currentThread() 用来获取当前线程
	 */
	public static void main(String[] args) {
		
		// 创建启动线程
		RunnableThread runnableThread = new RunnableThread();
		Thread thread = new Thread(runnableThread);
		thread.start();
		
		// 创建启动线程
		ExtendsThread extendsThread = new ExtendsThread();
		extendsThread.start();
		
		for (int i = 0; i < 10; i++) {
			System.out.println("main thread:" + i);
		}
		
		Callable<Integer> myCallable = new MyCallable();
		// 使用 FutureTask 来包装 MyCallable 对象
        FutureTask<Integer> ft = new FutureTask<Integer>(myCallable);
        // 创建启动线程
        Thread ftThread = new Thread(ft);
        ftThread.start();
        try {
        	// 取得新创建的新线程中的call()方法返回的结果
            int sum = ft.get();            
            System.out.println("sum = " + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
	}
	
}

/**
 * 实现 Runnable 接口创建线程
 */
class RunnableThread implements Runnable {
	// 实现方式好处，避免了单继承的局限性，在定义线程时，建议使用实现方式
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println("runnable thread:" + i);
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

/**
 * 继承 Thread 类创建线程
 */
class ExtendsThread extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println("extends thread:" + i);
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

/**
 * 使用 Callable 和 Future 创建线程
 */
class MyCallable implements Callable<Integer> {
    private int i = 0;
    
    // 与 run() 方法不同的是，call() 方法具有返回值
    @Override
    public Integer call() {
        int sum = 0;
        for (; i < 10; i++) {
            System.out.println("callable thread: " + i);
            sum += i;
            try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
        }
        return sum;
    }
}

